﻿#include "sys.h"
#include "TurnTable.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_rcc.h"
#include "misc.h"
#include <string.h>

#define __USART_NAME_TurnTable__ USART2                            //转台通信串口名，目前使用USART2，避免编译错误
#define __USART_RCC_PERIPH_USART_TurnTable__ RCC_APB1Periph_USART2 //转台串口时钟标识
#define __USART_RCC_PERIPH_GPIO_TurnTable__ RCC_APB2Periph_GPIOA   //串口所在引脚组的时钟标识
#define __USART_PERIPH_GPIO_TurnTable__ GPIOA                      //串口所在引脚组标识
#define __USART_PERIPH_USART_TX_TurnTable__ GPIO_Pin_2             //串口发送数据引脚标识
#define __USART_PERIPH_USART_RX_TurnTable__ GPIO_Pin_3             //串口接收数据引脚标识
#define __USART_NVIC_TurnTable__ USART2_IRQn                       //转台串口优先级标识

typedef struct
{
  unsigned char data[16];
} TurnTable_Data;

//-------------------------------------数据缓冲区------------------------------
unsigned char TurnTable_Uart_Buffer[256];         //串口接收缓冲区，结构为循环队列，掩码为0xfff
unsigned short TurnTable_Uart_Buffer_begin = 0;   //串口接收缓冲区头部坐标，代表开始解析的位置
unsigned short TurnTable_Uart_Buffer_nowAt = 0;   //串口接收缓冲区当前解析位置，用于避免重复解析
unsigned short TurnTable_Uart_Buffer_end = 0;     //串口接收缓冲区尾部坐标，代表收到的最新数据的后一位
unsigned short TurnTable_Uart_Buffer_mask = 0xff; //串口接收缓冲区掩码
TurnTable_Data TurnTable_dataBuffer[16];          //接收数据缓冲区，结构为循环队列，为上层模块服务，
unsigned char TurnTable_dataBuffer_begin = 0;     //接收数据缓冲区开始坐标
unsigned char TurnTable_dataBuffer_end = 0;       ////接收数据缓冲区结束坐标
unsigned char TurnTable_dataBuffer_mask = 0xf;    //接收数据缓冲区掩码
TurnTable_Data TurnTable_sendQueue[16];           //转台指令发送队列，结构为循环队列，掩码为0xf
unsigned char TurnTable_sendQueue_begin = 0;      //发送队列的开始坐标，指向将要发送的指令
unsigned char TurnTable_sendQueue_end = 0;        //发送队列的结束坐标，指向最新的指令的后一位
unsigned char TurnTable_sendQueue_mask = 0xf;     //发送队列掩码
//----------------------------------------------------------------------------

//----------------------------------计时器------------------------------------
unsigned short remainTime_sendTurnTableData = 0; //发送转台数据剩余时间
unsigned short remainTime_getCurrentState = 0;//查询当前状态剩余时间
unsigned short remainTime_getRunningState = 0;//查询运行状态剩余时间
unsigned short interval_sendTurnTableData = 30;  //发送转台数据间隔，单位ms，不得少于30ms
unsigned short interval_getCurrentState = 1000; // 查询当前状态间隔，单位ms
unsigned short interval_getRunningState = 2000;//查询运行状态间隔，单位ms
//----------------------------------------------------------------------------
////加入以下代码,支持printf函数,而不需要选择use MicroLIB
//#if 1
//#pragma import(__use_no_semihosting)
////标准库需要的支持函数
//struct __FILE
//{
//  int handle;
//};

//FILE __stdout_turnTable;
////定义_sys_exit()以避免使用半主机模式
//void _sys_exit_turnTable(int x)
//{
//  (void)x;
////  x = x;
//}
////重定义fputc函数
//int fputc_turnTable(int ch, FILE *f)
//{
//  while((__USART_NAME__->SR&0X40)==0);//循环发送,直到发送完毕
//  __USART_NAME__->DR = (unsigned char) ch;
//  return ch;
//}
//#endif

void TurnTable_connectToTurnTable(void)//添加连接转台指令到发送队列
{
  unsigned char data[16];
  memset(data,0,16);
  data[0]=0xdd;
  data[1]=0x00;
  data[2]=0x55;
  data[15]=0xce;
  TurnTable_appendTurnTableDataToSendQueue(data);
}

void TurnTable_getRunningState(void)//添加查询运行状态指令到发送队列
{
  unsigned char data[16];
  memset(data,0,16);
  data[0]=0xdd;
  data[1]=0x01;
  data[2]=0x16;
  data[15]=0x0c;
  TurnTable_appendTurnTableDataToSendQueue(data);
}

void TurnTable_getCurrentState(void)//添加查询当前状态指令到发送队列
{
  unsigned char data[16];
  memset(data,0,16);
  data[0]=0xdd;
  data[1]=0x01;
  data[2]=0x13;
  data[15]=0x0f;
  TurnTable_appendTurnTableDataToSendQueue(data);
}

void TurnTable_getTurnTableState(void)//尝试发送查询转台状态的一系列指令
{
  if(0==remainTime_getCurrentState)//尝试发送查询当前状态
    {
      remainTime_getCurrentState=interval_getCurrentState;
      TurnTable_getCurrentState();
    }
  if(0==remainTime_getRunningState)//尝试发送查询运行状态
    {
      remainTime_getRunningState=interval_getRunningState;
      TurnTable_getRunningState();
    }
}

void TurnTable_sendDataToTurnTable(void) //尝试发送数据到转台
{
  unsigned char i = 0;
  unsigned char *src = TurnTable_sendQueue[TurnTable_sendQueue_begin].data;
  if (TurnTable_sendQueue_end == TurnTable_sendQueue_begin) //如果发送队列为空则直接返回
  {
    return;
  }
  if (0 != remainTime_sendTurnTableData) //若剩余时间不等于0，则还不能发送数据，直接返回
  {
    return;
  }
  remainTime_sendTurnTableData=interval_sendTurnTableData;//重置计时器时间
  for (i = 0; i < 16; ++i)//发送数据
  {
    while (USART_GetFlagStatus(__USART_NAME_TurnTable__, USART_FLAG_TC) == RESET)
      ;
    USART_SendData(__USART_NAME_TurnTable__, src[i]);
  }
  TurnTable_sendQueue_begin = (TurnTable_sendQueue_begin + 1) & TurnTable_sendQueue_mask;//发送队列大小减一
}

void TurnTable_appendTurnTableDataToSendQueue(unsigned char *source)
{
  unsigned char i=0;
  unsigned char *target = TurnTable_sendQueue[TurnTable_sendQueue_end].data;
  for(i=0;i<16;++i)
  {
    target[i]=source[i];
  }
  TurnTable_sendQueue_end=(TurnTable_sendQueue_end+1)&TurnTable_sendQueue_mask;
//  TurnTable_sendDataToTurnTable();
}

unsigned char TurnTable_isDataBufferEmpty(void) //数据缓冲区为空则返回0，否则返回1
{
  return !((TurnTable_dataBuffer_end - TurnTable_dataBuffer_begin) & TurnTable_dataBuffer_mask);
}

void TurnTable_dataBufferGetData(unsigned char *target) //从数据缓冲区得到一条数据
{
  unsigned char i = 0;
  unsigned char* source=TurnTable_dataBuffer[TurnTable_dataBuffer_begin].data;
  for (i = 0; i < 16; ++i)
  {
    target[i] = source[i];
  }
  TurnTable_dataBuffer_begin = (TurnTable_dataBuffer_begin + 1) & TurnTable_dataBuffer_mask;
}

unsigned short TurnTable_getSerialPortBufferSize(void) //得到串口数据缓冲区大小
{
  return (TurnTable_Uart_Buffer_end - TurnTable_Uart_Buffer_begin) & TurnTable_Uart_Buffer_mask;
}

void TurnTable_dataBufferDropData(const unsigned short len) //串口数据缓冲区丢弃数据
{
  if (0 == len)
  {
    return;
  }
  if (TurnTable_getSerialPortBufferSize() < len)
  {
    TurnTable_Uart_Buffer_begin = TurnTable_Uart_Buffer_end = 0;
  }
  else
  {
    TurnTable_Uart_Buffer_begin = (TurnTable_Uart_Buffer_begin + len) & TurnTable_Uart_Buffer_mask;
  }
}

void TurnTable_dataBufferNowAtMoveToNext(void)
{
  TurnTable_Uart_Buffer_nowAt = (TurnTable_Uart_Buffer_nowAt + 1) & TurnTable_Uart_Buffer_mask;
}

unsigned char TurnTable_dataCheck(void)
{
  unsigned char sum = 0;
  unsigned char i = 0;
  for (i = 0; i < 16; ++i)
  {
    sum += TurnTable_Uart_Buffer[i];
  }
  return !sum;
}

void TurnTable_newTurnTableFeedback(void) //添加新的转台反馈到数据缓冲区
{
  unsigned char i = 0;
  unsigned char *tar=TurnTable_dataBuffer[TurnTable_dataBuffer_end].data;
  for (i = 0; i < 16; ++i)
  {
    tar[i] = TurnTable_Uart_Buffer[i]; //复制串口缓冲区数据到数据缓冲区
  }
  TurnTable_dataBuffer_end = (TurnTable_dataBuffer_end + 1) & TurnTable_dataBuffer_mask; //数据缓冲区大小加一
  TurnTable_dataBufferDropData(16);                                                      //串口缓冲区丢弃16字节数据
}

void TurnTable_decode(void)
{
  while (TurnTable_Uart_Buffer_nowAt != TurnTable_Uart_Buffer_end) //如果当前解析位置不等于串口缓冲区结束位置，则开始解析
  {
    if (TurnTable_Uart_Buffer_nowAt == TurnTable_Uart_Buffer_begin) //如果当前解析位置与串口数据缓冲区开始位置相等
    {
      if (0xdd != TurnTable_Uart_Buffer[TurnTable_Uart_Buffer_begin]) //如果串口缓冲区的开始不是0xdd时直接丢弃
      {
        TurnTable_dataBufferDropData(1);                           //串口缓冲区丢弃1字节数据
        TurnTable_Uart_Buffer_nowAt = TurnTable_Uart_Buffer_begin; //当前解析位置保持与开始位置相等
      }
      else //串口缓冲区开始是0xdd
      {
        TurnTable_dataBufferNowAtMoveToNext(); //解析位置移动到下一个字节
      }
    }
    else
    {
      if (((TurnTable_Uart_Buffer_nowAt - TurnTable_Uart_Buffer_begin) & TurnTable_Uart_Buffer_mask) >= 15) //如果解析位置超过转台数据包大小，则认为取得完整的数据包
      {
        if (TurnTable_dataCheck()) //校验数据，若无误则向上提交
        {
          TurnTable_newTurnTableFeedback(); //向上提交数据
        }
        else //若出错，则丢弃一字节数据
        {
          TurnTable_dataBufferDropData(1); //串口缓冲区丢弃1字节数据
        }
      }
      else
      {
        TurnTable_dataBufferNowAtMoveToNext(); //解析位置移动到下一个字节
      }
    }
  }
}

//初始化函数暂时不做更改，等待真实环境后再说，其中的各项参数要与新的串口一致
void TurnTable_uart_init(void)
{ //初始化转台通信串口
  //GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

  RCC_APB2PeriphClockCmd(__USART_RCC_PERIPH_USART_TurnTable__ | __USART_RCC_PERIPH_GPIO_TurnTable__, ENABLE); //使能USART1，GPIOA时钟
  //USART2_TX
  GPIO_InitStructure.GPIO_Pin = __USART_PERIPH_USART_TX_TurnTable__; //PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                  //复用推挽输出
  GPIO_Init(__USART_PERIPH_GPIO_TurnTable__, &GPIO_InitStructure); //初始化GPIOA.9

  //USART2_RX
  GPIO_InitStructure.GPIO_Pin = __USART_PERIPH_USART_RX_TurnTable__; //PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;              //浮空输入
  GPIO_Init(__USART_PERIPH_GPIO_TurnTable__, &GPIO_InitStructure);   //初始化GPIOA.10

  //Usart1 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = __USART_NVIC_TurnTable__;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //抢占优先级3
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //IRQ通道使能
  NVIC_Init(&NVIC_InitStructure);                           //根据指定的参数初始化VIC寄存器

  //USART 初始化设置

  USART_InitStructure.USART_BaudRate = 9600;                                      //串口波特率
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;                     //字长为8位数据格式
  USART_InitStructure.USART_StopBits = USART_StopBits_1;                          //一个停止位
  USART_InitStructure.USART_Parity = USART_Parity_No;                             //无奇偶校验位
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                 //收发模式

  USART_Init(__USART_NAME_TurnTable__, &USART_InitStructure);      //初始化转台串口
  USART_ITConfig(__USART_NAME_TurnTable__, USART_IT_RXNE, ENABLE); //开启转台串口接受中断
  USART_Cmd(__USART_NAME_TurnTable__, ENABLE);                     //使能转台串口
}

void TurnTable_init(void)//转台连接初始化
{
  char i=0;
  memset(TurnTable_Uart_Buffer,0,sizeof (TurnTable_Uart_Buffer));
  for(i=0;i<16;++i)
    {
      memset(TurnTable_dataBuffer[i].data,0,16);
      memset(TurnTable_sendQueue[i].data,0,16);
    }
  TurnTable_connectToTurnTable();


}

//转台串口中断服务程序
//记得把串口中断处理函数的名字更改为stm32中规定的中断函数处理的名字
void __USART_IRQHandler_TurnTable__(void)
{
  if (USART_GetITStatus(__USART_NAME_TurnTable__, USART_IT_RXNE) != RESET)
  {
    TurnTable_Uart_Buffer[TurnTable_Uart_Buffer_end] = USART_ReceiveData(__USART_NAME_TurnTable__);
    TurnTable_Uart_Buffer_end = (TurnTable_Uart_Buffer_end + 1) & TurnTable_Uart_Buffer_mask;
  }
}
